/**
 * 图像处理
 */

#include "naskfunc.h"
#include "graphic.h"
#include "mtask.h"

/**
 * 初始化调色板
 */
void init_palette(void) {
	/* static声明的变量是"静态"的  在程序结束之前一直"存在" */
	static unsigned char table_rgb[16 * 3] = { //
			0x00, 0x00, 0x00, /*  0:黑 */
			0xff, 0x00, 0x00, /*  1:亮红 */
			0x00, 0xff, 0x00, /*  2:亮绿 */
			0xff, 0xff, 0x00, /*  3:亮黄 */
			0x00, 0x00, 0xff, /*  4:亮蓝 */
			0xff, 0x00, 0xff, /*  5:亮紫 */
			0x00, 0xff, 0xff, /*  6:浅亮蓝 */
			0xff, 0xff, 0xff, /*  7:白 */
			0xc6, 0xc6, 0xc6, /*  8:亮灰 */
			0x84, 0x00, 0x00, /*  9:暗红 */
			0x00, 0x84, 0x00, /* 10:暗绿 */
			0x84, 0x84, 0x00, /* 11:暗黄 */
			0x00, 0x00, 0x84, /* 12:暗青 */
			0x84, 0x00, 0x84, /* 13:暗紫 */
			0x00, 0x84, 0x84, /* 14:浅暗蓝 */
			0x84, 0x84, 0x84 /* 15:暗灰 */
			};
	unsigned char table_color[216 * 3];
	int r, g, b; //三原色
	set_palette(0, 15, table_rgb);
	for (b = 0; b < 6; b++) {
		for (g = 0; g < 6; ++g) {
			for (r = 0; r < 6; ++r) {
				table_color[(r + g * 6 + b * 36) * 3 + 0] = r * 51;
				table_color[(r + g * 6 + b * 36) * 3 + 1] = g * 51;
				table_color[(r + g * 6 + b * 36) * 3 + 2] = b * 51;
			}
		}
	}
	set_palette(16, 231, table_color);
	return;
}

/**
 * 设置调色板
 */
void set_palette(int start, int end, unsigned char *rgb) {
	int i, eflags;
	eflags = io_load_eflags();
	io_cli();	//设置if=0，不响应可屏蔽中断
	io_out8(0x03c8, start);
	for (i = start; i <= end; ++i) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);
	return;
}

/**
 * 以屏幕左上方为(0,0)坐标在屏幕上绘制像素点
 * char *vram 图形显示地址
 * xsize 每行的列数
 * unsigned char c 要填充的颜色 (实际上它是该颜色在调色板中的下标)
 * int x0 X轴开始位置
 * int x1 X轴结束位置
 * int y0 y轴开始位置
 * int y1 y轴结束位置
 * x表示列 y表示行	例如320*200表示的就是整个屏幕分成200行，每行有320列
 */
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) {
	int x, y;

	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++) {
			vram[y * xsize + x] = c;
		}
	}
}

/**
 * 初始化屏幕
 * char *vram 图形显示地址
 * int xsize X轴大小
 * int ysize Y轴大小
 */
void init_screen8(char* vram, int xsize, int ysize) {
	boxfill8(vram, xsize, COL8_008484, 0, 0, xsize - 1, ysize - 29);
	boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 28, xsize - 1, ysize - 28);
	boxfill8(vram, xsize, COL8_FFFFFF, 0, ysize - 27, xsize - 1, ysize - 27);
	boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 26, xsize - 1, ysize - 1);
	boxfill8(vram, xsize, COL8_FFFFFF, 3, ysize - 24, 59, ysize - 24);
	boxfill8(vram, xsize, COL8_FFFFFF, 2, ysize - 24, 2, ysize - 4);
	boxfill8(vram, xsize, COL8_848484, 3, ysize - 4, 59, ysize - 4);
	boxfill8(vram, xsize, COL8_848484, 59, ysize - 23, 59, ysize - 5);
	boxfill8(vram, xsize, COL8_000000, 2, ysize - 3, 59, ysize - 3);
	boxfill8(vram, xsize, COL8_000000, 60, ysize - 24, 60, ysize - 3);
	boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize - 4, ysize - 24);
	boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize - 4);
	boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize - 3, xsize - 4, ysize - 3);
	boxfill8(vram, xsize, COL8_FFFFFF, xsize - 3, ysize - 24, xsize - 3, ysize - 3);
}

/**
 *  在屏幕上输出单个字符
 *
 * vram	图像缓冲区首地址
 * xsize 是每行的列数
 * x, y 要输出的字符在屏幕上的坐标
 * c	字符的颜色
 * font	指向要输出的字符(我不知道应该怎么解释这个参数, 它实际上是一个字符指针
 *						它所指向的是要显示某个字符需要绘制的具体像素, 额。。
 *						好吧, 不明白的请参考书上P94最下面的'A'字符的图形)
 */
void putfont8(char *vram, int xsize, int x, int y, char c, char *font) {
	int i;
	char *p, d; //data
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) {
			p[0] = c;
		}
		if ((d & 0x40) != 0) {
			p[1] = c;
		}
		if ((d & 0x20) != 0) {
			p[2] = c;
		}
		if ((d & 0x10) != 0) {
			p[3] = c;
		}
		if ((d & 0x08) != 0) {
			p[4] = c;
		}
		if ((d & 0x04) != 0) {
			p[5] = c;
		}
		if ((d & 0x02) != 0) {
			p[6] = c;
		}
		if ((d & 0x01) != 0) {
			p[7] = c;
		}
	}
	return;
}

/**
 *  在屏幕上输出单个字符
 *
 * vram	图像缓冲区首地址
 * xsize 是每行的列数
 * x, y 要输出的字符在屏幕上的坐标
 * c	字符的颜色
 * font	指向要输出的字符(我不知道应该怎么解释这个参数, 它实际上是一个字符指针
 *						它所指向的是要显示某个字符需要绘制的具体像素, 额。。
 *						好吧, 不明白的请参考书上P94最下面的'A'字符的图形)
 */
void putfont8_ch(char *vram, int xsize, int x, int y, char c, char *font) {
	int i;
	char *p, d; //data
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i * 2];
		if ((d & 0x80) != 0) {
			p[0] = c;
		}
		if ((d & 0x40) != 0) {
			p[1] = c;
		}
		if ((d & 0x20) != 0) {
			p[2] = c;
		}
		if ((d & 0x10) != 0) {
			p[3] = c;
		}
		if ((d & 0x08) != 0) {
			p[4] = c;
		}
		if ((d & 0x04) != 0) {
			p[5] = c;
		}
		if ((d & 0x02) != 0) {
			p[6] = c;
		}
		if ((d & 0x01) != 0) {
			p[7] = c;
		}
	}
	return;
}

/* 输出ascii码字符串
 * vram	图像缓冲区首地址 	xsize是每行的列数
 * x, y 要输出的字符串在屏幕上的起始坐标
 * c	字符的颜色			s	要输出的字符串内容
 */
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) {
	extern char hankaku[4096];
	struct TASK *task = task_now();
	char *language = (char *) *((int *) 0x0fe8), *font;
	int k, t; // 区号，点号

	if (task->langmode == 0) { // 英语
		for (; *s != 0x00; s++) {
			putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
			x += 8;
		}
	}
	if (task->langmode == 1) { // 日语
		for (; *s != 0x00; s++) {
			if (task->sbcCaseByteOne == 0) {
				if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) {
					task->sbcCaseByteOne = *s;
				} else {
					putfont8(vram, xsize, x, y, c, language + *s * 16);
				}
			} else {
				if (0x81 <= task->sbcCaseByteOne && task->sbcCaseByteOne <= 0x9f) {
					k = (task->sbcCaseByteOne - 0x81) * 2;
				} else {
					k = (task->sbcCaseByteOne - 0xe0) * 2 + 62;
				}
				if (0x40 <= *s && *s <= 0x7e) {
					t = *s - 0x40;
				} else if (0x80 <= *s && *s <= 0x9e) {
					t = *s - 0x80 + 63;
				} else {
					t = *s - 0x9f;
					k++;
				}
				task->sbcCaseByteOne = 0;
				font = language + 256 * 16 + (k * 94 + t) * 32;
				putfont8(vram, xsize, x - 8, y, c, font); // 左半部分
				putfont8(vram, xsize, x, y, c, font + 16); //右半部分
			}
			x += 8;
		}
	}
	if (task->langmode == 2) { // 日语EUC
		for (; *s != 0x00; s++) {
			if (task->sbcCaseByteOne == 0) {
				if (0x81 <= *s && *s <= 0xfe) {
					task->sbcCaseByteOne = *s;
				} else {
					putfont8(vram, xsize, x, y, c, language + *s * 16);
				}
			} else {
				k = task->sbcCaseByteOne - 0xa1;
				t = *s - 0xa1;
				task->sbcCaseByteOne = 0;
				font = language + 256 * 16 + (k * 94 + t) * 32;
				putfont8(vram, xsize, x - 8, y, c, font); // 左半部分
				putfont8(vram, xsize, x, y, c, font + 16); //右半部分
			}
			x += 8;
		}
	}
	if (task->langmode == 3) {
		for (; *s != 0x00; s++) {
			if (task->sbcCaseByteOne == 0) {
				if (*s >= 0xa0) {
					task->sbcCaseByteOne = *s;
				} else {
					putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
				}
			} else {
				k = task->sbcCaseByteOne - 0xa0;
				t = *s - 0xa0;
				task->sbcCaseByteOne = 0;
				font = language + ((k - 1) * 94 + (t - 1)) * 32;
				putfont8_ch(vram, xsize, x - 8, y, c, font);
				putfont8_ch(vram, xsize, x, y, c, font + 1);
			}
			x += 8;
		}
	}
	return;
}

/**
 * 初始化鼠标图形
 */
void init_mouse_cursor8(char *mouse, char bc) {
	static char cursor[16][16] = { /**/
	"**************..",/**/
	"*OOOOOOOOOOO*...",/**/
	"*OOOOOOOOOO*....",/**/
	"*OOOOOOOOO*.....",/**/
	"*OOOOOOOO*......",/**/
	"*OOOOOOO*.......",/**/
	"*OOOOOOO*.......",/**/
	"*OOOOOOOO*......",/**/
	"*OOOO**OOO*.....",/**/
	"*OOO*..*OOO*....",/**/
	"*OO*....*OOO*...",/**/
	"*O*......*OOO*..",/**/
	"**........*OOO*.",/**/
	"*..........*OOO*",/**/
	"............*OO*",/**/
	".............***" /**/
	};

	int x, y;

	for (y = 0; y < 16; y++) {
		for (x = 0; x < 16; x++) {
			if (cursor[y][x] == '*') {
				mouse[y * 16 + x] = COL8_000000;
			}

			if (cursor[y][x] == 'O') {
				mouse[y * 16 + x] = COL8_FFFFFF;
			}

			if (cursor[y][x] == '.') {
				mouse[y * 16 + x] = bc;
			}
		}
	}
	return;
}

/** 显示某一图形
 *	vram 图像缓冲区首地址	vxsize 每行的列数
 *	pxsize	要显示的图形的列数	pysize 要显示的图形的行数
 *	px0, py0 要显示的图形的左上角在屏幕上的坐标
 *	buf	要显示的图形		bxsize 图形每行的元素数
 */
void putblock8_8(char *vram, int vxsize, int pxsize, int pysize, int px0, int py0, char *buf, int bxsize) {
	int x, y;
	for (y = 0; y < pysize; y++) {
		for (x = 0; x < pxsize; x++) {
			vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
		}
	}
	return;
}

/**
 * 绘制直线
 */
void drawLine(struct SHEET *sht, int x0, int y0, int x1, int y1, int col) {
	int i, x, y, len, dx, dy;

	dx = x1 - x0;
	dy = y1 - y0;
	x = x0 << 10;
	y = y0 << 10;

	if (dx < 0) {
		dx = -dx;
	}
	if (dy < 0) {
		dy = -dy;
	}
	if (dx >= dy) { // 比较起点与终点来确定直线的长度
		len = dx + 1;
		dx = x0 > x1 ? -1024 : 1024; // 2 << 10 == 1024
		dy = y0 <= y1 ? ((y1 - y0 + 1) << 10) / len : ((y1 - y0 - 1) << 10) / len;
	} else {
		len = dy + 1;
		dy = y0 > y1 ? -1024 : 1024;
		dx = x0 <= x1 ? ((x1 - x0 + 1) << 10) / len : ((x1 - x0 - 1) << 10) / len;
	}

	for (i = 0; i < len; i++) {
		sht->buf[(y >> 10) * sht->bxsize + (x >> 10)] = col;
		x += dx;
		y += dy;
	}
}

